﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Configuration;
using System.Web.Mvc;
using System.Web.Routing;
using ZQNB.Common.Caching;

namespace ZQNB.Common.Web
{
    public class MvcHelper
    {
        /// <summary>
        /// 是否是异步请求
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <returns></returns>
        public static bool IsAjaxRequest(ControllerContext controllerContext)
        {
            return controllerContext.HttpContext.Request.IsAjaxRequest();
        }

        /// <summary>
        /// 是否是ChildAction
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <returns></returns>
        public static bool IsChildAction(ControllerContext controllerContext)
        {
            return controllerContext.IsChildAction;
        }

        /// <summary>
        /// 检测上下文是否应该逃脱
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <param name="escapeChildAction"></param>
        /// <param name="escapeAjaxRequest"></param>
        /// <returns></returns>
        public static bool CheckEscape(ControllerContext controllerContext, bool escapeChildAction = true, bool escapeAjaxRequest = true)
        {
            if (controllerContext.HttpContext == null
                || controllerContext.HttpContext.Request == null
                || controllerContext.HttpContext.Request.Url == null
                || controllerContext.HttpContext.Request.Url.PathAndQuery.EndsWith(".ico", StringComparison.InvariantCultureIgnoreCase))
            {
                return true;
            }

            if (escapeChildAction)
            {
                if (controllerContext.IsChildAction)
                {
                    return true;
                }
            }

            if (escapeAjaxRequest)
            {
                if (controllerContext.HttpContext.Request.IsAjaxRequest())
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 检测上下文中是否包含Attitude
        /// </summary>
        /// <param name="filterContext"></param>
        /// <param name="attributeType"></param>
        /// <returns></returns>
        public static bool HasAttribute(ActionExecutingContext filterContext, Type attributeType)
        {
            return filterContext.ActionDescriptor.GetCustomAttributes(attributeType, true).Length > 0
                || filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(attributeType, true).Length > 0;
        }

        /// <summary>
        /// 获取当前路由值
        /// </summary>
        /// <returns></returns>
        public static RouteData GetRouteData()
        {
            RequestContext requestContext = HttpContext.Current.Request.RequestContext;
            RouteData routeData = requestContext.RouteData;
            return routeData;
        }

        /// <summary>
        /// 获取当前的UrlHelper
        /// </summary>
        /// <returns></returns>
        public static UrlHelper GetCurrentUrlHelper()
        {
            RequestContext requestContext = HttpContext.Current.Request.RequestContext;
            return new UrlHelper(requestContext);
        }

        /// <summary>
        /// 尝试从当前路由中获取键的值
        /// 检索不到则返回""
        /// </summary>
        /// <param name="routeData"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetRouteValue(RouteData routeData, string key)
        {
            string value = routeData.Values[key] == null
                                   ? (routeData.DataTokens[key] == null ? "" : routeData.DataTokens[key].ToString())
                                   : routeData.Values[key].ToString();
            return value;
        }

        /// <summary>
        /// 获取当前的IdentityName
        /// </summary>
        /// <returns></returns>
        public static string GetIdentityName()
        {
            string identityName = HttpContext.Current == null
                                           ? (HttpContext.Current.User == null ? "" : HttpContext.Current.User.Identity.Name)
                                           : HttpContext.Current.User.Identity.Name;
            return identityName;
        }

        /// <summary>
        /// 获取当前的URI
        /// </summary>
        /// <returns></returns>
        public static Uri GetCurrentUri()
        {
            var uri = HttpContext.Current.Request.Url;
            return uri;
        }

        /// <summary>
        /// 获取当前的queryString
        /// </summary>
        /// <returns></returns>
        public static string GetQueryString()
        {
            string queryString = HttpContext.Current.Request.Url.Query;
            return queryString;
        }

        /// <summary>
        /// 组织一个来自客户端的请求
        /// </summary>
        /// <returns></returns>
        public static NbMvcRequest MakeRequest()
        {
            //HttpContext.Current.Items获取可用于在 HTTP 请求过程中在 IHttpModule 接口和 IHttpHandler 接口之间组织和共享数据的键/值集合。
            string key = MakeCacheKey<NbMvcRequest>();
            NbMvcRequest request = perRequestCacheManager.Get<NbMvcRequest>(key);

            if (request == null)
            {
                RouteData routeData = GetRouteData();
                request = CollectRequest(routeData);
                perRequestCacheManager.Set(key, request);
            }

            return request;
        }

        private static NbMvcRequest CollectRequest(RouteData routeData)
        {
            NbMvcRequest request = new NbMvcRequest();

            request.Area = GetRouteValue(routeData, "area");
            request.DomainUri = HttpContext.Current.Request.Url.Authority;
            request.Site = GetRouteValue(routeData, "site");
            
            //20140916 fix menu bugs
            //space互访的问题！！路由中必须指定owner
            string theOwner = GetRouteValue(routeData, "owner");
            if (string.IsNullOrWhiteSpace(theOwner))
            {
                theOwner = HttpContext.Current.Request.Params["owner"];
            }
            request.Owner = theOwner;

            request.Controller = GetRouteValue(routeData, "controller");
            request.Action = GetRouteValue(routeData, "action");

            request.QueryString = HttpContext.Current.Request.Url.Query;
            request.IdentityName = HttpContext.Current == null
                                           ? (HttpContext.Current.User == null ? "" : HttpContext.Current.User.Identity.Name)
                                           : HttpContext.Current.User.Identity.Name;

            return request;
        }
        
        /// <summary>
        /// 获取当前的Url
        /// /home/index
        /// </summary>
        /// <returns></returns>
        public static string GetCurrentUrl()
        {
            var uri = GetCurrentUri();
            return uri.PathAndQuery;
        }
        
        public static string MakeRouteUrl(string routeName, string site, string area, string controller, string action, string owner, string moreQuery)
        {
            var urlHelper = GetCurrentUrlHelper();
            string url = urlHelper.RouteUrl(routeName, new { site = site, area = area, action = action, controller = controller, owner = owner });
            if (string.IsNullOrWhiteSpace(url))
            {
                throw new ArgumentException("生成路由的参数不合法！（比如area, controller, action并不存在等情况）");
            }
            
            if (!string.IsNullOrWhiteSpace(moreQuery))
            {
                if (!url.Contains("?"))
                {
                    url = url + "?";
                }

                url = url + "&" + moreQuery;
                url = url.Replace("?&", "?").Replace("&&", "&");
            }

            return url;
        }
        
        public static bool CompareUrlEqual(string url1, string url2)
        {
            bool equal = url1.Equals(url2, StringComparison.OrdinalIgnoreCase);
            return equal;
            //// space/admin/home/index
            //// /space/admin/home/index
            ////fixed 前后缀，认为其相等
            //bool equal = url1.TrimStart('/').Equals(url2.TrimStart('/'), StringComparison.OrdinalIgnoreCase);
            //return equal;
        }
        
        #region 客户端Ip

        public static bool IsVisitFromLocal()
        {
            return "127.0.0.1" == GetRequestClientIp();
        }

        /// <summary>
        /// 获取当前请求端的IP地址
        /// </summary>
        /// <returns></returns>
        public static string GetRequestClientIp()
        {
            lock (_lock)
            {
                string userIP = "";
                HttpContext context = HttpContext.Current;
                if (context == null)
                {
                    return userIP;
                }

                HttpRequest Request = HttpContext.Current.Request;
                if (Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != "")
                {
                    userIP = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                }
                else if (Request.ServerVariables["REMOTE_ADDR"] != "")
                {
                    userIP = Request.ServerVariables["REMOTE_ADDR"];
                }

                if (string.IsNullOrEmpty(userIP))
                {
                    userIP = Request.UserHostAddress;
                }

                return ReplaceRequestClientIp(userIP);
            }
        }

        private static string ReplaceRequestClientIp(string input)
        {
            string result = input;
            if ("::1".Equals(input, StringComparison.InvariantCultureIgnoreCase))
            {
                result = "127.0.0.1";
            }
            else if ("localhost".Equals(input, StringComparison.InvariantCultureIgnoreCase))
            {
                result = "127.0.0.1";
            }
            return result;
        }
        
        #endregion

        private static readonly object _lock = new object();
        private static readonly CacheHelper cacheHelper = new CacheHelper();
        private static readonly PerRequestCacheManager perRequestCacheManager = new PerRequestCacheManager();

        private static string MakeCacheKey<T>()
        {
            string key = cacheHelper.MakeCacheKey<T>();
            return key;
        }

        public static void SetRequestContextValue<T>(T value)
        {
            lock (_lock)
            {
                string key = MakeCacheKey<T>();
                perRequestCacheManager.Set(key, value);
            }
        }

        public static T GetRequestContextValue<T>()
        {
            lock (_lock)
            {
                string key = MakeCacheKey<T>();
                return perRequestCacheManager.Get<T>(key);
            }
        }

    }
}
